import clippy from '../clippyjs'
import { distinctUntilChanged, map } from 'rxjs'
import { Injectable } from '@angular/core'
import { Logger, LogService, ConfigService, HotkeysService } from 'tabby-core'

// 定义一个常量，存储Clippy资源的CDN地址
const CDN = 'https://rawcdn.githack.com/pi0/clippyjs/d88943d529410114c9cea7f01e05de40254cd914'

@Injectable({ providedIn: 'root' }) // 使用@Injectable装饰器，使ClippyService可以被注入
export class ClippyService {
    private visible = true // 定义一个私有变量，表示Clippy是否可见
    private agent: any // 定义一个私有变量，用于存储Clippy代理对象
    private logger: Logger // 定义一个私有变量，用于记录日志

    // ClippyService的构造函数
    constructor (
        private config: ConfigService, // 注入ConfigService服务
        log: LogService, // 注入LogService服务
        hotkeys: HotkeysService, // 注入HotkeysService服务
    ) {
        this.logger = log.create('clippy') // 初始化logger
        this.loadAgent() // 调用loadAgent方法加载Clippy代理

        // 监听配置变化，重新加载Clippy代理
        this.config.changed$.pipe(
            map(() => this.config.store.clippyPlugin.agent), // 从配置中获取Clippy代理类型
            distinctUntilChanged(), // 只有在配置变化时才继续
        ).subscribe(() => this.loadAgent()) // 重新加载Clippy代理

        // 动态加载Clippy样式
        const link = document.createElement('link')
        link.rel = 'stylesheet'
        link.href = `${CDN}/assets/clippy.css`
        document.querySelector('head').appendChild(link)

        // 每10秒让Clippy代理执行动画
        setInterval(() => {
            this.agent?.animate()
        }, 30000)

        // 监听热键事件，执行相应的操作
        hotkeys.hotkey$.subscribe(h => {
            if (h === 'toggle-clippy') {
                this.toggle() // 切换Clippy显示状态
            }
        })
    }

    // 异步方法，加载Clippy代理
    async loadAgent () {
        // const type = this.config.store.clippyPlugin.agent // 获取代理类型
        //由于最开始this.config.store是没有值的，所以如果检查到store是undefined，就直接采用default的值
        let type = ''
        if (this.config.store !== undefined) {
            type = this.config.store.clippyPlugin.agent
        } else {
            //this.config.getDefaults()返回的是一个对象，所以要用['clippyPlugin']['agent']来获取值
            type = this.config.getDefaults()['clippyPlugin']['agent']
        }


        // const type = this.config.store.clippyPlugin.agent // 获取代理类型
        this.logger.info(`Loading agent: ${type}`) // 记录日志
        await this.hide() // 隐藏当前代理
        clippy.load(type, agent => {
            this.agent = agent // 设置代理对象
            this.visible = true // 设置可见状态
            agent.show() // 显示代理
            this.speak('Hello!') // 让代理说话
        }, undefined, `${CDN}/assets/agents/`) // 设置代理资源路径
    }

    // 显示Clippy代理
    show () {
        if (!this.agent) {
            return // 如果代理不存在，直接返回
        }
        this.agent.show() // 显示代理
        this.visible = true // 设置可见状态
        this.logger.info('Shown clippy') // 记录日志
    }

    // 异步方法，隐藏Clippy代理
    async hide () {
        if (!this.agent) {
            return // 如果代理不存在，直接返回
        }
        await new Promise(r => this.agent.hide(false, r)) // 隐藏代理
        this.visible = false // 设置不可见状态
        this.logger.info('Hidden clippy') // 记录日志
    }

    // 异步方法，切换Clippy的显示状态
    async toggle () {
        if (this.visible) {
            await this.hide() // 如果当前可见，则隐藏
        } else {
            await this.show() // 如果当前不可见，则显示
        }
    }

    // 让Clippy代理说话
    speak (what: string) {
        this.logger.info(`Speaking: ${what}`) // 记录日志
        this.agent?.speak(what) // 让代理说话
    }

    // 让Clippy代理执行动画
    ThinkAnimate () {
        this.agent?.animateWithName("CheckingSomething") // 让代理执行动画
    }
}
